/*
 * StateTable.cpp
 *
 * Stores all states and transitions of the state machine
 * and controls the state machine itself
 *
 * Author: Zachary Masiello
 * Author: Peter-John Rowe
 */

#include "StateTable.h"

// Constructor
StateTable::StateTable() {
	runActivity = false;
}

// Destructor
StateTable::~StateTable() {
	// Deallocate matrix
}

// Gets the run activity boolean pertaining to the state
bool StateTable::getRunActivity(IState* state) {
	switch(state->getID()) {
	case SPEED_MODE_STATE_ID:
		runActivity = speedRunActivity;
		break;
	case DIST_MODE_STATE_ID:
		runActivity = distRunActivity;
		break;
	case TIME_MODE_STATE_ID:
		runActivity = timeRunActivity;
		break;
	}
	return runActivity;
}

// Sets the run activity boolean pertaining to the state
void StateTable::setRunActivity(IState* state,bool run) {
	switch(state->getID()) {
	case SPEED_MODE_STATE_ID:
		speedRunActivity = run;
		break;
	case DIST_MODE_STATE_ID:
		distRunActivity = run;
		break;
	case TIME_MODE_STATE_ID:
		timeRunActivity = run;
		break;
	}
}

// Accepts an event, accesses the matrix for the list of transitions associated with
// the current state. Traverses these transitions to see if the event triggers the id.
// If the event triggers the transition, the guard is evaluated. If guard is evaluated to true,
// accept the transition and set the current state to next state
void StateTable::accept(IEvent* event) {
	bool notAccepted = true;
	matrixIterator = matrix.find(currentState);
	StateTransitions s = matrixIterator->second;
	for(int i = 0; i < (int)s.size() && notAccepted; i++) {
		if(event->getEventID() == s[i]->getEventID()) {
			// Evaluate guard
			if(s[i]->guard()) {
				// Execute current state's exit action
				setRunActivity(currentState,false);
				switch(currentState->getID()) {
				case FULL_RESET_STATE_ID: break;
				case INITIAL_DATA_STATE_ID:break;
				case UNIT_SET_STATE_ID: break;
				case SET_TIRE_CONF_STATE_ID: break;
				case SPEED_MODE_STATE_ID: break;
				case TIME_MODE_STATE_ID: break;
				case DIST_MODE_STATE_ID: break;
				case SET_TIRE_RUN_STATE_ID: break;
				case OPERATING_STATE_ID: break;
				}

				// Execute transition's action
				setCurrentState(s[i]->accept());
				// Execute the new state's entry action
				notAccepted = false;
			} else {
				cout << "Guard failed!" << endl;
			}
		}
	}
}

// Assigns state
void StateTable::assignState(IState* newState) {
	matrix[newState] = StateTransitions();
}

// Assigns transition
void StateTable::assignTransition(IState* state,Transition* transition) {
	matrixIterator = matrix.find(state);

	if ( matrixIterator == matrix.end() ) {
		assignState(state);
		assignTransition(state,transition);
	} else {
		StateTransitions s = matrixIterator->second;
		s.push_back(transition);
		matrix[state] = s;
	}
}

// Sets the current state
void StateTable::setCurrentState(IState* state) {
	if (currentState != NULL) {
		cout << "Leaving " << currentState->getStateName() << endl << endl;
	}
	currentState = state;
	cout << "Entering " << currentState->getStateName() << endl;
	setRunActivity(currentState,true);
	currentState->entryAction();
	//currentState->activity();
	pthread_create(&stateThread, NULL, (void*(*)(void*))&IState::run, (void*)currentState);

}

// Sets the initial state
void StateTable::setDefaultInitialState(IState* initialState) {
	setCurrentState(initialState);
}

// Gets the current state
IState* StateTable::getCurrentState() {
	return currentState;
}
